// 实现这个项目的构建任务
// Grunt 的入口文件
// 用于定义一些需要 Grunt执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的形参，内部提供一些创建任务时可以用到的 API
const loadGruntTasks = require('load-grunt-tasks')
const sass = require('sass')
const useref = require('useref')

const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}

module.exports = grunt => {
  grunt.initConfig({
    // 清除任务
    clean: {
      dist: 'dist/**',
      temp: 'temp/**'
    },
    // 样式目标配置
    sass: {
      options: {
        sourceMap: true,
        // 意思是用那个模块去解析我们的代码
        implementation: sass
      },
      main: {
        files: [{
          expand: true,
          cwd: 'src/assets/styles',
          src: '*.scss', //所有 scss 文件
          dest: 'temp/assets/styles',  // 输出到此目录下
          ext: '.css' // 修改扩展名
        }]
      }
    },
    // 脚本编译目标配置
    babel: {
      options: {
        sourceMap: true,
        presets: ['@babel/preset-env']

      },
      main: {
        files: [{
          expand: true,
          cwd: 'src/assets/scripts',
          src: '*.js', //所有 js 文件
          dest: 'temp/assets/scripts'  // 输出到此目录下
        }]
      }
    },
    // 页面模板编译
    web_swig: {
      options: {
        swigOptions: {
          cache: false
        },
        getData: function () {
          return data;
        }
      },
      main: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: '*.html', //所有 html 文件
          dest: 'temp'  // 输出到此目录下
        }]
      }
    },
    // js 压缩
    uglify: {
      options: {
        mangle: true, //混淆变量名
        comments: 'false' // false（删除全部注释），some（保留@preserve @license @cc_on等注释）
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'temp/assets/scripts',
          src: '*.js',
          dest: 'dist/assets/scripts'
        }]
      }
    },
    // 样式文件的压缩
    cssmin: {
      main: {
        options: {
          mangle: false
        },
        expand: true,
        cwd: 'temp/assets/styles/', // 压缩那个文件夹里的文件
        src: '*.css', // 压缩那个文件
        dest: 'dist/assets/styles/', // 放压缩后文件的文件夹
        ext: '.css' // 压缩后文件的的名字
      }
    },
    // 模板文件的压缩
    htmlmin: {
      options: {
        collapseWhitespace: true,
        minifyCSS: true,
        minifyJS: true,
        removeComments: true, // 移除注释
        removeCommentsFromCDATA: true,// 移除来自字符数据的注释
        collapseWhitespace: true, // 无用空格
        collapseBooleanAttributes: true, // 失败的布尔属性
        removeAttributeQuotes: true, // 移除属性引号  有些属性不可移走引号
        removeRedundantAttributes: true, // 移除多余的属性
        useShortDoctype: true, // 使用短的跟元素
        removeEmptyAttributes: true, // 移除空的属性
        removeOptionalTags: true // 移除可选附加标签
      },
      main: {
        expand: true,
        cwd: 'dist/',
        src: ['*.html'],
        dest: 'dist'
      }
    },
    // 图片编译任务
    imagemin: {
      main: {
        files: [{
          expand: true,
          cwd: 'src/assets/images',
          src: ['**'],
          dest: 'dist/assets/images'
        }, {
          expand: true,
          cwd: 'src/assets/fonts',
          src: ['**'],
          dest: 'dist/assets/fonts'
        }]
      }
    },
    // public 目录拷贝任务
    copy: {
      main: {
        files: [{
          expand: true,
          cwd: 'public',
          src: ['**'],
          dest: 'dist/'
        }]
      }
    },
    // 监视文件修改后执行相应的任务
    watch: {
      script: {
        // 需要监视的文件路径
        files: ['src/assets/scripts/*.js'],
        // 需要执行的任务
        tasks: ['babel']
      },
      style: {
        // 需要监视的文件路径
        files: ['src/assets/styles/*.scss'],
        // 需要执行的任务
        tasks: ['sass']
      },
      page: {
        // 需要监视的文件路径
        files: ['src/*.html'],
        // 需要执行的任务
        tasks: ['web_swig']
      },
      image: {
        files: ['src/assets/images/**'],
        tasks: ['imagemin']
      },
      font: {
        files: ['src/assets/fonts/**'],
        tasks: ['imagemin']
      }
    },
    // 开发服务器
    browserSync: {
      dev: {
        bsFiles: {
          src: [
            'temp/assets/styles/*.css',
            'temp/assets/script/*.js',
            'temp/assets/images/**',
            'temp/assets/fonts/**',
            'temp/*.html'
          ]
        },
        options: {
          port: 13500,
          watchTask: true,
          server: {
            baseDir: ['temp', 'src', 'public'],
            routes: {
              '/node_modules': 'node_modules'
            }
          }
        }
      }
    }
  })
  
  loadGruntTasks(grunt)
  // 外部引用任务
  grunt.registerTask('useref', function () {
    const done = this.async()
    const htmls = []
    grunt.file.recurse('temp', function (abspath, rootdir, subdir, filename) {
      if (/\.html$/.test(filename)) {
        htmls.push(abspath)
      }
    })
    htmls.forEach(html => {
      const data = grunt.file.read(html, { encoding: 'utf8' })
      const [code, result] = useref(data)
      for (const resultKey in result) {
        if (!result.hasOwnProperty(resultKey)) {
          return
        }

        const targetKeys = Object.keys(result[resultKey])
        targetKeys.forEach(vendor => {
          const target = result[resultKey][vendor]
          let buffer = ''
          for (const targetKey in target) {
            if (!target.hasOwnProperty(targetKey)) {
              return
            }
            const targetItems = target[targetKey]
            targetItems.forEach(item => {
              if (/\/node_modules/.test(item)) {
                item = item.replace(/\//, '')
              } else {
                item = `temp/${item}`
              }
              buffer += grunt.file.read(item)
            })
          }
          const absolutePath = `temp/${vendor}`
          if (!grunt.file.exists(absolutePath)) {
            grunt.file.write(absolutePath, buffer)
            console.log(`file:${absolutePath} write success`)
          }
        })
      }
      grunt.file.write(html.replace(/temp/, 'dist'), code)
    })
    done()
  })
  // 编译任务
  grunt.registerTask('compile', ['sass', 'babel', 'web_swig'])
  // 压缩任务
  grunt.registerTask('compression', ['uglify', 'cssmin', 'htmlmin'])
  // 打包任务
  grunt.registerTask('build', ['clean', 'compile', 'useref', 'uglify', 'cssmin', 'htmlmin', 'imagemin', 'copy'])
  // 开发服务器
  grunt.registerTask('serve', ['compile', 'browserSync', 'watch'])
}
